# import the necessary packages
import numpy as np
import time
import cv2
import os
from os import listdir
from os.path import isfile, join
from matplotlib import pyplot as plt
# Define our imshow function
def imshow(title = "Image", image = None, size = 10):
w, h = image.shape[0], image.shape[1]
aspect_ratio = w/h
plt.figure(figsize=(size * aspect_ratio,size))
plt.imshow(cv2.cvtColor(image, cv2.COLOR_BGR2RGB))
plt.title(title)
plt.show()

Steps Invovled
# Load the COCO class labels our YOLO model was trained on
labelsPath = "Datasets/YOLOv3/yolo/coco.names"
LABELS = open(labelsPath).read().strip().split("\n")
# We now need to initialize a list of colors to represent each possible class label
COLORS = np.random.randint(0, 255, size=(len(LABELS), 3), dtype="uint8")
print("Loading YOLO weights...")
weights_path = "Datasets/YOLOv3/yolo/yolov3.weights"
cfg_path = "Datasets/YOLOv3/yolo/yolov3.cfg"
# Create our blob object
net = cv2.dnn.readNetFromDarknet(cfg_path, weights_path)
# Set our backend
net.setPreferableBackend(cv2.dnn.DNN_BACKEND_OPENCV)
# net.setPreferableTarget(cv2.dnn.DNN_TARGET_CPU)
print("Our YOLO Layers")
ln = net.getLayerNames()
# There are 254 Layers
print(len(ln), ln)
Loading YOLO weights... Our YOLO Layers 254 ['conv_0', 'bn_0', 'relu_1', 'conv_1', 'bn_1', 'relu_2', 'conv_2', 'bn_2', 'relu_3', 'conv_3', 'bn_3', 'relu_4', 'shortcut_4', 'conv_5', 'bn_5', 'relu_6', 'conv_6', 'bn_6', 'relu_7', 'conv_7', 'bn_7', 'relu_8', 'shortcut_8', 'conv_9', 'bn_9', 'relu_10', 'conv_10', 'bn_10', 'relu_11', 'shortcut_11', 'conv_12', 'bn_12', 'relu_13', 'conv_13', 'bn_13', 'relu_14', 'conv_14', 'bn_14', 'relu_15', 'shortcut_15', 'conv_16', 'bn_16', 'relu_17', 'conv_17', 'bn_17', 'relu_18', 'shortcut_18', 'conv_19', 'bn_19', 'relu_20', 'conv_20', 'bn_20', 'relu_21', 'shortcut_21', 'conv_22', 'bn_22', 'relu_23', 'conv_23', 'bn_23', 'relu_24', 'shortcut_24', 'conv_25', 'bn_25', 'relu_26', 'conv_26', 'bn_26', 'relu_27', 'shortcut_27', 'conv_28', 'bn_28', 'relu_29', 'conv_29', 'bn_29', 'relu_30', 'shortcut_30', 'conv_31', 'bn_31', 'relu_32', 'conv_32', 'bn_32', 'relu_33', 'shortcut_33', 'conv_34', 'bn_34', 'relu_35', 'conv_35', 'bn_35', 'relu_36', 'shortcut_36', 'conv_37', 'bn_37', 'relu_38', 'conv_38', 'bn_38', 'relu_39', 'conv_39', 'bn_39', 'relu_40', 'shortcut_40', 'conv_41', 'bn_41', 'relu_42', 'conv_42', 'bn_42', 'relu_43', 'shortcut_43', 'conv_44', 'bn_44', 'relu_45', 'conv_45', 'bn_45', 'relu_46', 'shortcut_46', 'conv_47', 'bn_47', 'relu_48', 'conv_48', 'bn_48', 'relu_49', 'shortcut_49', 'conv_50', 'bn_50', 'relu_51', 'conv_51', 'bn_51', 'relu_52', 'shortcut_52', 'conv_53', 'bn_53', 'relu_54', 'conv_54', 'bn_54', 'relu_55', 'shortcut_55', 'conv_56', 'bn_56', 'relu_57', 'conv_57', 'bn_57', 'relu_58', 'shortcut_58', 'conv_59', 'bn_59', 'relu_60', 'conv_60', 'bn_60', 'relu_61', 'shortcut_61', 'conv_62', 'bn_62', 'relu_63', 'conv_63', 'bn_63', 'relu_64', 'conv_64', 'bn_64', 'relu_65', 'shortcut_65', 'conv_66', 'bn_66', 'relu_67', 'conv_67', 'bn_67', 'relu_68', 'shortcut_68', 'conv_69', 'bn_69', 'relu_70', 'conv_70', 'bn_70', 'relu_71', 'shortcut_71', 'conv_72', 'bn_72', 'relu_73', 'conv_73', 'bn_73', 'relu_74', 'shortcut_74', 'conv_75', 'bn_75', 'relu_76', 'conv_76', 'bn_76', 'relu_77', 'conv_77', 'bn_77', 'relu_78', 'conv_78', 'bn_78', 'relu_79', 'conv_79', 'bn_79', 'relu_80', 'conv_80', 'bn_80', 'relu_81', 'conv_81', 'permute_82', 'yolo_82', 'identity_83', 'conv_84', 'bn_84', 'relu_85', 'upsample_85', 'concat_86', 'conv_87', 'bn_87', 'relu_88', 'conv_88', 'bn_88', 'relu_89', 'conv_89', 'bn_89', 'relu_90', 'conv_90', 'bn_90', 'relu_91', 'conv_91', 'bn_91', 'relu_92', 'conv_92', 'bn_92', 'relu_93', 'conv_93', 'permute_94', 'yolo_94', 'identity_95', 'conv_96', 'bn_96', 'relu_97', 'upsample_97', 'concat_98', 'conv_99', 'bn_99', 'relu_100', 'conv_100', 'bn_100', 'relu_101', 'conv_101', 'bn_101', 'relu_102', 'conv_102', 'bn_102', 'relu_103', 'conv_103', 'bn_103', 'relu_104', 'conv_104', 'bn_104', 'relu_105', 'conv_105', 'permute_106', 'yolo_106']
The input to the network is a called blob object.
The function cv.dnn.blobFromImage(img, scale, size, mean) transforms the image into a blob:
blob = cv.dnn.blobFromImage(img, 1/255.0, (416, 416), swapRB=True, crop=False)
It has the following parameters:
Note A blob is a 4D numpy array object (images, channels, width, height). The image below shows the red channel of the blob. You notice the brightness of the red jacket in the background.
print("Starting Detections...")
# Get images located in ./images folder
mypath = "Datasets/YOLOv3/images/"
file_names = [f for f in listdir(mypath) if isfile(join(mypath, f))]
# Loop through images run them through our classifer
for file in file_names:
# load our input image and grab its spatial dimensions
image = cv2.imread(mypath+file)
(H, W) = image.shape[:2]
# we want only the *output* layer names that we need from YOLO
ln = net.getLayerNames()
ln = [ln[i[0] - 1] for i in net.getUnconnectedOutLayers()]
# Now we contruct our blob from our input images
blob = cv2.dnn.blobFromImage(image, 1 / 255.0, (416, 416), swapRB=True, crop=False)
# We set our input to our image blob
net.setInput(blob)
# Then we run a forward pass through the network
layerOutputs = net.forward(ln)
# we initialize our lists for our detected bounding boxes, confidences, and classes
boxes = []
confidences = []
IDs = []
# Loop over each of the layer outputs
for output in layerOutputs:
# Loop over each detection
for detection in output:
# Obtain class ID and probality of detection
scores = detection[5:]
classID = np.argmax(scores)
confidence = scores[classID]
# We keep only the most probably predictions
if confidence > 0.75:
# We scale the bounding box coordinates relative to the image
# Note: YOLO actually returns the center (x, y) of the bounding
# box followed by the width and height of the box
box = detection[0:4] * np.array([W, H, W, H])
(centerX, centerY, width, height) = box.astype("int")
# Get the the top and left corner of the bounding box
# Remember we alredy have the width and height
x = int(centerX - (width / 2))
y = int(centerY - (height / 2))
# Append our list of bounding box coordinates, confidences and class IDs
boxes.append([x, y, int(width), int(height)])
confidences.append(float(confidence))
IDs.append(classID)
# Now we apply non-maxima suppression to reduce overlapping bounding boxes
idxs = cv2.dnn.NMSBoxes(boxes, confidences, 0.5, 0.3)
# We proceed once a detection has been found
if len(idxs) > 0:
# iterate over the indexes we are keeping
for i in idxs.flatten():
# Get the bounding box coordinates
(x, y) = (boxes[i][0], boxes[i][1])
(w, h) = (boxes[i][2], boxes[i][3])
# Draw our bounding boxes and put our class label on the image
color = [int(c) for c in COLORS[IDs[i]]]
cv2.rectangle(image, (x, y), (x + w, y + h), color, 3)
text = "{}: {:.4f}".format(LABELS[IDs[i]], confidences[i])
cv2.putText(image, text, (x, y - 5), cv2.FONT_HERSHEY_SIMPLEX, 0.5, color, 2)
# show the output image
imshow("YOLO Detections", image, size = 12)
Starting Detections...
indices = cv.dnn.NMSBoxes( bboxes, scores, score_threshold, nms_threshold[, eta[, top_k]]
Parameters